#include "int_util.h"

/****************************************************************************\
 * Private Functions
\****************************************************************************/

static int s_to_int(wchar_t c)
{
	switch(c)
	{
	case L'0': return 0;
	case L'1': return 1;
	case L'2': return 2;
	case L'3': return 3;
	case L'4': return 4;
	case L'5': return 5;
	case L'6': return 6;
	case L'7': return 7;
	case L'8': return 8;
	case L'9': return 9;
	case L'a': case L'A': return 10;
	case L'b': case L'B': return 11;
	case L'c': case L'C': return 12;
	case L'd': case L'D': return 13;
	case L'e': case L'E': return 14;
	case L'f': case L'F': return 15;
	default: return -1;
	}
}

static BOOL s_parse_oct(const wchar_t *str, size_t len, size_t *p_int)
{
	int factor = 1;
	int i, dig;

	*p_int = 0;
	for(i = len - 1; i >= 0; --i)
	{
		dig = s_to_int(str[i]);
		if(dig < 0 || dig > 7)
			return FALSE;

		*p_int += dig * factor;
		factor *= 8;
	}

	return TRUE;
}

static BOOL s_parse_hex(const wchar_t *str, size_t len, size_t *p_int)
{
	int factor = 1;
	int i, dig;

	*p_int = 0;
	for(i = len - 1; i >= 0; --i)
	{
		dig = s_to_int(str[i]);
		if(dig < 0 || dig > 0xF)
			return FALSE;

		*p_int += dig * factor;
		factor *= 16;
	}

	return TRUE;
}

static BOOL s_parse_dec(const wchar_t *str, size_t len, size_t *p_int)
{
	int factor = 1;
	int i, dig;

	*p_int = 0;
	for(i = len - 1; i >= 0; --i)
	{
		dig = s_to_int(str[i]);
		if(dig < 0 || dig > 9)
			return FALSE;

		*p_int += dig * factor;
		factor *= 10;
	}

	return TRUE;
}

/****************************************************************************\
 * Public Functions
\****************************************************************************/

BOOL is_int_dig(wchar_t c)
{
	switch(c)
	{
	case L'0': case L'1': case L'2': case L'3': case L'4':
	case L'5': case L'6': case L'7': case L'8': case L'9':
	case L'a': case L'b': case L'c': case L'd': case L'e': case L'f':
	case L'A': case L'B': case L'C': case L'D': case L'E': case L'F':
	case L'o': case L'O': case L'x': case L'X': case L'h': case L'H':
		return TRUE;
	default:
		return FALSE;
	}
}

BOOL parse_int(const wchar_t *str, size_t len, size_t *p_int)
{
	if(str[0] == L'0')
	{
		if(str[1] == L'x' || str[1] == L'X')
			return s_parse_hex(str + 2, len - 2, p_int);
		else if(str[len - 1] == L'h' || str[len - 1] == L'H')  // 0xxxxh is treat as hex
			return s_parse_hex(str + 1, len - 2, p_int);
		else
			return s_parse_oct(str + 1, len - 1, p_int);
	}
	else if(str[0] == L'o' || str[0] == L'O')
		return s_parse_oct(str + 1, len - 1, p_int);
	else if(str[len - 1] == L'h' || str[len - 1] == L'H')
		return s_parse_hex(str, len - 1, p_int);
	else
		return s_parse_dec(str, len, p_int);
}

size_t num_of_1_u8(u8 value)
{
	size_t i, n = 0;
	for(i = 0; i < 64; ++i, value >>= 1)
		if(value & 1)
			++n;

	return n;
}

BOOL decode_u4(byte *bytes, size_t *p_size, u4 *p_value)
{
	size_t sz;
	u4 val;

	if ((bytes[0] & 0x80) == 0)
	{
		sz = 1;
		val = (u4)bytes[0];
	}
	else if ((bytes[0] & 0xC0) == 0x80)
	{
		sz = 2;
		val =(u4)((bytes[0] & 0x3F) << 8 | bytes[1]);
	}
	else if ((bytes[0] & 0xE0) == 0xC0)
	{
		sz = 4;
		val = (u4)((bytes[0] & 0x1F) << 24
			| bytes[1] << 16 | bytes[2] << 8 | bytes[3]);
	}
	else
		return FALSE;

	if(p_size) *p_size = sz;
	if(p_value) *p_value = val;
	return TRUE;
}

BOOL decode_i4(byte *bytes, size_t *p_size, i4 *p_value)
{
	size_t sz;
	u4 u4val, sign_bits;
	i4 val;

	if(!decode_u4(bytes, &sz, &u4val))
		return FALSE;

	if ((u4val & 0x00000001) == 0)
	{
		val = (i4)(u4val >> 1);
	}
	else
	{
		switch(sz)
		{
		case 1: sign_bits = 0xFFFFFFC0; break;
		case 2: sign_bits = 0xFFFFE000; break;
		case 4: sign_bits = 0xF0000000; break;
		default: return FALSE;
		}

		val = (i4)((u4val >> 1) | sign_bits);
	}

	if(p_size) *p_size = sz;
	if(p_value) *p_value = val;
	return TRUE;
}
